package com.tcoiss.datafactory.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcoiss.common.core.domain.R;
import com.tcoiss.common.core.enums.ErroEnums;
import com.tcoiss.common.core.exception.CustomException;
import com.tcoiss.common.component.api.RemoteLogService;
import com.tcoiss.common.component.api.model.SchemeVO;
import com.tcoiss.common.log.annotation.SchemeLog;
import com.tcoiss.common.log.enums.BusinessType;
import com.tcoiss.datafactory.domain.ExecuteScheme;
import com.tcoiss.datafactory.domain.ExecuteWork;
import com.tcoiss.datafactory.mapper.ExecuteSchemeMapper;
import com.tcoiss.datafactory.service.IExecuteSchemeService;
import com.tcoiss.datafactory.service.IExecuteWorkService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 执行方案Service业务层处理
 *
 * @author zw
 * @date 2021-04-26
 */
@Service
public class ExecuteSchemeServiceImpl extends ServiceImpl<ExecuteSchemeMapper, ExecuteScheme> implements IExecuteSchemeService {

    @Autowired
    private IExecuteWorkService iExecuteWorkService;

    @Autowired
    private RemoteLogService remoteLogService;

    @Autowired
    private AsyncExecuteService asyncExecuteService;

    @Override
    public List<ExecuteScheme> queryList(ExecuteScheme executeScheme) {
        LambdaQueryWrapper<ExecuteScheme> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(executeScheme.getSchemeName())) {
            lqw.like(ExecuteScheme::getSchemeName, executeScheme.getSchemeName());
        }
        if (executeScheme.getExecuteType() != null) {
            lqw.eq(ExecuteScheme::getExecuteType, executeScheme.getExecuteType());
        }
        if (StringUtils.isNotBlank(executeScheme.getExecuteNumber())) {
            lqw.like(ExecuteScheme::getExecuteNumber, executeScheme.getExecuteNumber());
        }
        if (executeScheme.getStatus() != null) {
            lqw.eq(ExecuteScheme::getStatus, executeScheme.getStatus());
        }
        lqw.orderByDesc(ExecuteScheme::getCreateTime);
        return this.list(lqw);
    }

    @Override
    public R execute(SchemeVO vo) {
        //查询执行方案
        LambdaQueryWrapper<ExecuteScheme> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(vo.getExecuteNumber())) {
            lqw.eq(ExecuteScheme::getExecuteNumber, vo.getExecuteNumber());
        }
        if (vo.getExecuteType() != null) {
            lqw.eq(ExecuteScheme::getExecuteType, vo.getExecuteType());
        }
        List<ExecuteScheme> schemes = this.list(lqw);
        if (schemes == null || schemes.size() == 0) {
            return R.fail(ErroEnums.DATAERRO.getCode(), "未查询到相应的执行方案");
        }
        if (schemes.size() > 1) {
            return R.fail(ErroEnums.DATAERRO.getCode(), "存在多个执行方案");
        }
        ExecuteScheme scheme = schemes.get(0);
        //根据执行方案查询作业
        List<ExecuteWork> works = iExecuteWorkService.getWorksBySchemeId(scheme.getSchemeId());
        if (works == null || works.size() == 0) {
            return R.fail(ErroEnums.DATAERRO.getCode(), "方案: " + scheme.getSchemeName() + "下未查询到可执行的作业");
        }
        //获取上次方案执行成功的时间，以此为数据更新的起始时间
        R<Date> r = remoteLogService.getSchemeLogNewTime(scheme.getExecuteNumber());
        if(r.getCode()!=200){
            throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{scheme.getSchemeName(),},ErroEnums.APIERRO.getInfo() + r.getMsg());
        }
        boolean bool = false;
        vo.setLastExecuteTime(r.getData());
        // todo 根据执行策略，执行作业 1.串行 2.并行 3.异步
        switch (scheme.getExecuteStrategy()) {
            case 1:
                for (ExecuteWork work : works) {
                    if(work.getWorkType()==2&&!bool){
                        break;
                    }
                    boolean flag = iExecuteWorkService.executeWork(work, vo);
                    //上一个作业执行
                    if(flag&&work.getWorkType()==1){
                        bool = flag;
                    }
                }
                break;
            case 2:
                for (ExecuteWork work : works) {

                }
                break;
            default:
                break;
        }
        return R.ok(true);
    }

    @Override
    public R handExecute(ExecuteScheme executeScheme) {
//        if (executeScheme.getExecuteType() != 3) {
//            throw new DataException(ErroEnums.DATAERRO.getCode(), new Object[]{executeScheme.getSchemeName()}, "当前方案不是手工执行方式无法手工执行");
//        }
        // todo 请求下来先将当前方案执行状态改为执行中 先查询执行状态是否为可执行
        if(executeScheme.getExecuteStatus().equals("0")){
            SchemeVO vo = new SchemeVO();
            vo.setExecuteNumber(executeScheme.getExecuteNumber());
            vo.setExecuteType(executeScheme.getExecuteType());
            //todo 将执行状态改为执行中
            executeScheme.setExecuteStatus("1");
            this.updateById(executeScheme);
            //异步执行方案，优先修改执行状态 并相应前端 ，方案的执行结果体现到日志中
            asyncExecuteService.execute(vo);
            return R.ok();
        }
        return R.fail("方案正在执行中");
    }

    @Override
    public Map<String, Object> querySchemeWorks(SchemeVO vo) {
        Map<String, Object> map = new HashMap<>();
        //查询执行方案
        LambdaQueryWrapper<ExecuteScheme> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(vo.getExecuteNumber())) {
            lqw.eq(ExecuteScheme::getExecuteNumber, vo.getExecuteNumber());
        }
        if (vo.getExecuteType() != null) {
            lqw.eq(ExecuteScheme::getExecuteType, vo.getExecuteType());
        }
        ExecuteScheme scheme = this.getOne(lqw);
        if (scheme == null) {
            return null;
        }
        //根据执行方案查询作业
        List<ExecuteWork> works = iExecuteWorkService.getWorksBySchemeId(scheme.getSchemeId());
        map.put("workNum", works.size());
        map.put("schemeName", scheme.getSchemeName());
        return map;
    }

    @Override
    public ExecuteScheme querySchemeByNumber(SchemeVO vo) {
        //查询执行方案
        LambdaQueryWrapper<ExecuteScheme> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(vo.getExecuteNumber())) {
            lqw.eq(ExecuteScheme::getExecuteNumber, vo.getExecuteNumber());
            if (vo.getExecuteType() != null) {
                lqw.eq(ExecuteScheme::getExecuteType, vo.getExecuteType());
            }
            return this.getOne(lqw);
        }
        return null;

    }

    @Override
    public boolean updateUseStatus(List<Long> asList, Integer status) {
        if (asList != null & status != null) {
            for (Long id : asList) {
                ExecuteScheme ew = getById(id);
                if (ew.getStatus() != status) {
                    ew.setStatus(status);
                    this.updateById(ew);
                }
            }
            return true;
        }
        return false;
    }

}
